package com.offcn.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.offcn.search.dao.SearchMapper;
import com.offcn.search.pojo.SkuInfo;
import com.offcn.search.service.SkuService;
import com.offcn.sellergoods.feign.ItemFeign;
import com.offcn.sellergoods.pojo.Item;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.*;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;

@Service
public class SkuServiceImpl implements SkuService {

    @Autowired
    private ItemFeign itemFeign;

    @Autowired
    private SearchMapper searchMapper;

    /**
     * 作用：用来实现查询
     */
    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Override
    public void importSkuData() {
        // 将所有item查询 通过远程调用实现
        List<Item> itemList = itemFeign.findAll().getData();

        // 准备导入的集合
        ArrayList<SkuInfo> skuList = new ArrayList<>();

        // 将 itemList 中的每个对象的属性值 赋值 给 skuList中的每个对象
        for (Item item : itemList) {  // 源对象
            SkuInfo  skuInfo = new SkuInfo();  // 目标对象
            // 复制属性值，要求：属性名相同，属性类型相同
            BeanUtils.copyProperties(item,skuInfo);

            // json格式 字符串 转换为 Map 对象
            Map<String,Object> specMap = JSON.parseObject(item.getSpec(), Map.class);
            skuInfo.setSpecMap(specMap);

            skuList.add(skuInfo);
        }

        // 导入
        searchMapper.saveAll(skuList);


    }

    @Override
    public Map search(Map<String, String> searchMap) {
        // 获取关键字
        String keywords = searchMap.get("keywords");
        // 非空验证
        if (StringUtils.isEmpty(keywords)) {
            keywords = "华为";
        }

        // 实现搜索
        // a. 创建查询对象构建器
        //    作用：
        //       1.设定查询条件，排序，分组条件，过滤条件，分页, 高亮 等...
        //       2.可以用来获取查询对象
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        // b0. 设定查询条件  通过match方法来匹配 title 字段 ，匹配的值是 keywords 变量
        queryBuilder.withQuery(QueryBuilders.matchQuery("title",keywords));

        // b1. 设定分类的分组条件
        // skuCategoryGroup 表示分组识别名
        if(StringUtils.isEmpty(searchMap.get("category"))) {
            queryBuilder.addAggregation(AggregationBuilders.terms("skuCategoryGroup").field("category"));

        }
        // b2. 设定品牌的分组条件
        if (StringUtils.isEmpty(searchMap.get("brand"))) {
            queryBuilder.addAggregation(AggregationBuilders.terms("skuBrandGroup").field("brand").size(100));
        }
        int specGroupCount=0;
        List<String> specValues=new ArrayList<>();
        if (!CollectionUtils.isEmpty(searchMap.keySet())) {
            for (String key : searchMap.keySet()) {
                // key  spec_网络    value 移动3G
                if (key.startsWith("spec_")) {  // 这是规格
                    //把规格名称加入list集合
                   specValues.add(key.substring(5));
                }
            }
        }
        // b3 设定规格分组条件

            queryBuilder.addAggregation(AggregationBuilders.terms("skuSpecGroup").field("spec.keyword"));


        // b4 设定过滤查询条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        // 品牌条件
        if (!StringUtils.isEmpty(searchMap.get("brand"))){ // 品牌参数的非空验证
            boolQueryBuilder.filter(QueryBuilders.matchQuery("brand",searchMap.get("brand")));
        }
        // 分类条件
        if (!StringUtils.isEmpty(searchMap.get("category"))){ // 分类参数的非空验证
            boolQueryBuilder.filter(QueryBuilders.matchQuery("category",searchMap.get("category")));
        }
        // 规格条件
        // 规定 规格名 spec_ 开始
        Set<String> keySet = searchMap.keySet();
        if (!CollectionUtils.isEmpty(keySet)) {
            for (String key : keySet) {
                // key  spec_网络    value 移动3G
                if (key.startsWith("spec_")) {  // 这是规格
                    // 获取 规格名
                    String specKeyName = key.substring(5);
                    boolQueryBuilder.filter(QueryBuilders.matchQuery("specMap." + specKeyName + ".keyword", searchMap.get(key)));
                }
            }
        }
        // 价格 接收的格式: 最小值-最大值  ，如果是 最大值为*  表示没有上限
        String prices = searchMap.get("price");
        if (!StringUtils.isEmpty(prices)) {
            String[] priceArr = prices.split("-");
            if (priceArr[1].equals("*")) {  // 没有上限
                boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(priceArr[0]));
            }else{
                boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").from(priceArr[0],true).to(priceArr[1],false));
            }
        }
        // 查询对象构建器和过滤查询对象构建器整合
        queryBuilder.withFilter(boolQueryBuilder);

        // b5 设定分页
        Integer pageNum = null;
        Integer pageSize = null;

        if (searchMap.get("pageNum") != null) {
            pageNum = Integer.parseInt(searchMap.get("pageNum"));
        }
        if (pageNum == null) {
            pageNum = 1;
        }

        if (searchMap.get("pageSize") != null) {
            pageSize = Integer.parseInt(searchMap.get("pageSize"));
        }
        if (pageSize == null) {
            pageSize = 10;
        }
        // 注意：首页从0开始
        queryBuilder.withPageable(PageRequest.of(pageNum - 1,pageSize));

        // b6 排序
        // 获取排序字段
        String sortField = searchMap.get("sortField");
        String sortRule = searchMap.get("sortRule");
        if (!StringUtils.isEmpty(sortField) && !StringUtils.isEmpty(sortRule)) {
            queryBuilder.withSort(SortBuilders.fieldSort(sortField).order( sortRule.equals("ASC") ? SortOrder.ASC : SortOrder.DESC));
        }

        // b7 高亮查询
        // 手机  ==>  <span style="color:red">手机</span>
        queryBuilder.withHighlightFields(new HighlightBuilder.Field("title"));
        queryBuilder.withHighlightBuilder(new HighlightBuilder().preTags("<span style=\"color:red\">").postTags("</span>"));

        // c. 创建查询对象
        NativeSearchQuery query = queryBuilder.build();
        // d. 执行查询
        SearchHits<SkuInfo> searchHits = elasticsearchRestTemplate.search(query, SkuInfo.class);

        // 存储所有查询记录的 集合
        ArrayList<SkuInfo> skuInfos = new ArrayList<>();

        // 没有分页的结果
//        for (SearchHit<SkuInfo> searchHit : searchHits.getSearchHits()) {
//            skuInfos.add(searchHit.getContent());
//        }

        // 分页之后获取查询的分页数据
        SearchPage<SkuInfo> skuPage = SearchHitSupport.searchPageFor(searchHits, query.getPageable());
        for (SearchHit<SkuInfo> skuInfoSearchHit : skuPage.getContent()) {
            // 获取高亮查询的结果
            String highLightTitle = skuInfoSearchHit.getHighlightField("title").get(0);
            skuInfoSearchHit.getContent().setTitle(highLightTitle);
            skuInfos.add(skuInfoSearchHit.getContent());
        }

        // 定义一个集合用来存储分类的分组结果
        List<String> categoryGroupResultList = new ArrayList<>();
        if(StringUtils.isEmpty(searchMap.get("category"))) {
            // 获取分组查询的结果
            Terms terms = searchHits.getAggregations().get("skuCategoryGroup");
            for (Terms.Bucket bucket : terms.getBuckets()) {
                String groupResult = bucket.getKeyAsString();
                categoryGroupResultList.add(groupResult);
            }
        }

        // 定义一个集合用来存储品牌分组的结果
        List<String> brandGroupResultList = new ArrayList<>();
        // 获取品牌查询的结果
        if(StringUtils.isEmpty(searchMap.get("brand"))) {
            Terms brandTerms = (Terms) searchHits.getAggregations().get("skuBrandGroup");
            for (Terms.Bucket bucket : brandTerms.getBuckets()) {
                String brandResult = bucket.getKeyAsString();
                brandGroupResultList.add(brandResult);
            }
        }

        // 定义一个集合用来存储规格分组的结果
        Map<String, Set<String>> specGroupResultMap = new HashMap<>();
        // 将查询的出来的分组结果放入到一个集合中
        ArrayList<String> specList = new ArrayList<>();

            // 获取分组查询结果
            Terms specTerms = (Terms) searchHits.getAggregations().get("skuSpecGroup");
            for (Terms.Bucket bucket : specTerms.getBuckets()) {
                specList.add(bucket.getKeyAsString());
            }

            for (String spec : specList) {
                Map<String, String> specMap = JSON.parseObject(spec, Map.class);
                for (String key : specMap.keySet()) {
                    Set<String> valueSet = specGroupResultMap.get(key);
                    if (valueSet == null) {  // 不存在该key
                        valueSet = new HashSet<>();
                    }
                    valueSet.add(specMap.get(key));
                    if(specValues.indexOf(key)==-1) {
                        specGroupResultMap.put(key, valueSet);
                    }
                }
            }




        // 返回值
        HashMap resultMap = new HashMap<>();
        // 返回总的记录数
        resultMap.put("total",searchHits.getTotalHits());
        // 返回总记录数
        resultMap.put("totalElements",skuPage.getTotalElements());
        // 返回总的分页数
        resultMap.put("totlePages",skuPage.getTotalPages());
        // 返回查询的记录
        resultMap.put("rows",skuInfos);
        // 返回查询的分组结果
        resultMap.put("categoryGroup",categoryGroupResultList);
        // 返回查询的规格结果
        resultMap.put("specGroup",specGroupResultMap);
        // 返回查询品牌分组结果
        resultMap.put("brandGroup",brandGroupResultList);
        return resultMap;
    }
}
